import {featureEach, getType, polygon as turfPolygon, area as turfArea, booleanClockwise} from '@turf/turf';
import {FeatureTypes} from "./constants";

const MIN_POLYGON_AREA_PCT = 1 / 800;

export default function normalize(geojson, opt = {}) {

    let { minPolygonArea } = opt;

    const features = [];

    if (minPolygonArea == null) {
        const sumPolygonArea = getAutoMinPolygonArea(geojson);
        minPolygonArea = sumPolygonArea * MIN_POLYGON_AREA_PCT;
    }

    featureEach(geojson, (feature) => {

        const {properties, geometry} = feature;

        if (!geometry || !properties.name) return;

        const type = getType(feature);
        let {coordinates} = geometry;

        const newCoordinates = [];

        if (type === FeatureTypes.MultiPolygon || type === FeatureTypes.Polygon) {
            if (type === FeatureTypes.MultiPolygon) {
                // Fix abnormal MultiPolygon.
                // Too many sub rings are not presenting holes.
                // It's bug in geojson.
                if (coordinates.length === 1 && coordinates[0].length > 10) {
                    // re-map rings to normal polygons
                    coordinates = coordinates[0].map(polygon => [polygon]);
                }
            }

            if (type === FeatureTypes.Polygon) {
                coordinates = [coordinates];
            }

            const len = coordinates.length;

            coordinates.forEach(polygon => {
                if (minPolygonArea) {
                    let area;
                    try {
                        area = turfArea(turfPolygon(polygon));
                    } catch (e) {}

                    if (!area || area < minPolygonArea) {
                        return;
                    }
                }

                if (booleanClockwise(polygon[0])) {
                    polygon[0].reverse();
                }

                newCoordinates.push(polygon.map(coord => coord.map(lngLat => lngLat.map(v => +(v.toFixed(4))))));

            });

            features.push({
                geometry: {
                    type: FeatureTypes.MultiPolygon,
                    coordinates: newCoordinates
                },
                properties,
                type: feature.type
            })
        } else if(type === FeatureTypes.MultiLineString){
            features.push({
                geometry: {
                    type,
                    coordinates: coordinates.map(coord => [coord])
                },
                properties,
                type: feature.type
            });
        }

    });

    return {
        features,
        type: geojson.type
    }

}


function getAutoMinPolygonArea(geojson) {

    let sumArea = 0;

    featureEach(geojson, (feature) => {
        const {geometry} = feature;

        if (!geometry) return;

        const {coordinates} = feature.geometry;
        const type = getType(feature);

        if (type === FeatureTypes.MultiPolygon || type === FeatureTypes.Polygon) {

            coordinates.forEach(polygon => {
                try{
                   sumArea += turfArea(turfPolygon(polygon));
                } catch (e){}

            });
        }

    });

    return sumArea;
}